C++ 性能优化,简直太硬核了!

您所在的位置:网站首页 matlab uint32溢出 C++ 性能优化,简直太硬核了!

C++ 性能优化,简直太硬核了!

2023-04-03 08:00| 来源: 网络整理| 查看: 265

前言

性能优化不管是从方法论,还是从实践上都有很多东西。本文从 C++ 语本身入手,介绍了一些性能优化的方法,希望能做到简洁实用。

实例1

在开始本文的内容之前,让我们看段小程序:

// 获取一个整数对应10近制的位数 uint32_t digits10_v1(uint64_t v) { uint32_t result = 0; do { ++result; v /= 10; } while (v); return result; }

如果要对这段代码进行优化,你认为瓶颈会是什么呢?代码 -g -O2 后看一眼汇编:

Dump of assembler code for function digits10_v1(uint64_t): 0x00000000004008f0 : mov %rdi,%rdx 0x00000000004008f3 : xor %esi,%esi 0x00000000004008f5 : mov $0xcccccccccccccccd,%rcx 0x00000000004008ff : nop 0x0000000000400900 : mov %rdx,%rax 0x0000000000400903 : add $0x1,%esi 0x0000000000400906 : mul %rcx 0x0000000000400909 : shr $0x3,%rdx 0x000000000040090d : test %rdx,%rdx 0x0000000000400910 : jne 0x400900 0x0000000000400912 : mov %esi,%eax 0x0000000000400914 : retq /* 注:对于常数的除法操作,编译器一般会转换成乘法+移位的方式,即 a / b = a * (1/b) = a * (2^n / b) * (1 / 2^n) = a * (2^n / b) >> n. 这里的n=3, b=10, 2^n/b=4/5,0xcccccccccccccccd是编译器对4/5的定点算法表示 */

指令已经很少了,有多少优化空间呢?先不着急,看看下面这段代码

uint32_t digits10_v2(uint64_t v) { uint32_t result = 1; for (;;) { if (v < 10) return result; if (v < 100) return result + 1; if (v < 1000) return result + 2; if (v < 10000) return result + 3; // Skip ahead by 4 orders of magnitude v /= 10000U; result += 4; } } uint32_t digits10_v3(uint64_t v) { if (v < 10) return 1; if (v < 100) return 2; if (v < 1000) return 3; if (v < 1000000000000) { // 10^12 if (v < 100000000) { // 10^7 if (v < 1000000) { // 10^6 if (v < 10000) return 4; return 5 + (v >= 100000); // 10^5 } return 7 + (v >= 10000000); // 10^7 } if (v < 10000000000) { // 10^10 return 9 + (v >= 1000000000); // 10^9 } return 11 + (v >= 100000000000); // 10^11 } return 12 + digits10_v3(v / 1000000000000); // 10^12 }

写了一个小程序,digits10_v2 比 digits10_v1 快了 45%, digits10_v3 比digits10_v1 快了60%+。不难看出测试结论跟数据的取值范围相关,就本例来说数值越大,提升越明显。是什么原因呢?附测试程序:

int main() { srand(100); uint64_t digit10_array[ITEM_COUNT]; for( int i = 0; i < ITEM_COUNT; ++i ) { digit10_array[i] = rand(); } struct timeval start, end; // digits10_v1 uint64_t sum1 = 0; uint64_t time1 = 0; gettimeofday(&start,NULL); for( int i = 0; i < RUN_TIMES; ++i ) { sum1 += digits10_v1(digit10_array[i]); } gettimeofday(&end,NULL); time1 = ( end.tv_sec - start.tv_sec ) * 1000 * 1000 + end.tv_usec - start.tv_usec; // digits10_v2 uint64_t sum2 = 0; uint64_t time2 = 0; gettimeofday(&start,NULL); for( int i = 0; i < RUN_TIMES; ++i ) { sum2 += digits10_v2(digit10_array[i]); } gettimeofday(&end,NULL); time2 = ( end.tv_sec - start.tv_sec ) * 1000 * 1000 + end.tv_usec - start.tv_usec; // digits10_v3 uint64_t sum3 = 0; uint64_t time3 = 0; gettimeofday(&start,NULL); for( int i = 0; i < RUN_TIMES; ++i ) { sum3 += digits10_v3(digit10_array[i]); } gettimeofday(&end,NULL); time3 = ( end.tv_sec - start.tv_sec ) * 1000 * 1000 + end.tv_usec - start.tv_usec; cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3